package com.wanban.download.runnable

import android.text.TextUtils
import android.util.Log
import com.wanban.download.BuildConfig
import com.wanban.download.Params
import com.wanban.download.utils.PathUtils
import com.wanban.download.WBDownloadUtils
import com.wanban.download.base.BaseDownloadInterface
import com.wanban.download.listener.OnFileDownloadListener
import com.wanban.download.model.M3U8
import com.wanban.download.model.Ts
import com.wanban.download.utils.CacheM3U8Utils
import com.wanban.download.utils.DownloadConstants
import com.wanban.download.utils.NetworkUtils
import java.io.File
import java.io.FileNotFoundException
import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.ThreadPoolExecutor

/**
 * 多线程下载多文件
 */
class MultipleThreadDownloadMultipleFilesUtils(
    private val url: String,
    private val m3u8: M3U8,
    private val rootFilePath: String?,
    private val listener: OnFileDownloadListener,
    private val tag: String,
    private val header: Map<String, String>? = null
): BaseDownloadInterface(false) {

    // 数据库更新时间
    private var m3u8UpdateInterval = 0

    override fun startDownload(totalLength: Long) {
        isInterrupted = false
        currentDownloadLength = 0
        // TsList的路径
        val tsListDirFile = File(PathUtils.getTsListFileDirPath(rootFilePath))
        if (!tsListDirFile.exists()) {
            val createSuccess = tsListDirFile.mkdirs()
            if (!createSuccess) {
                listener.onError(url, DownloadConstants.ERROR_TS_FILE_CREATE)
                return
            }
        }
        if (isInterrupted) return
        listener.onStart(url)
        if (isInterrupted) return
        // 启动回调线程
        startProgressCallback()

        try {
            for (index in m3u8.tsList.indices) {
                if (isInterrupted) break
                val ts = m3u8.tsList[index]
                if (TextUtils.isEmpty(ts.url)) continue
                if (ts.complete) {
                    currentDownloadLength += ts.tsSize
                    continue
                }

                if (isInterrupted) break
                if (executors.isShutdown || executors.isTerminated) {
                    isInterrupted = true
                    break
                }
                executors.submit(createTsDownloadRunnable(ts, tsListDirFile))
            }
        } catch (e: RejectedExecutionException) {
            e.printStackTrace()
        } catch (e: Exception) {
            e.printStackTrace()
            if (isInterrupted || executors.isShutdown || executors.isTerminated) return
            listener.onError(url, "下载出现异常！")
        }
    }


    private fun createTsDownloadRunnable(ts: Ts, tsListDirFile: File): Runnable {
        val tsFilePath = tsListDirFile.absolutePath + File.separator + ts.getTsName()
        val tsUrl = ts.getTsUrl() ?: throw FileNotFoundException()
        val downloadFileUtils = SingleThreadDownloadSingleFileUtils(tsUrl, tsFilePath, object: OnFileDownloadListener {
            override fun onStart(url: String) {
            }
            override fun onProgress(url: String, speed: Long, currentLength: Long, percent: Float) {
                currentDownloadSpeed += speed
            }
            override fun onError(url: String, errorMsg: String) {
                onDoError(ts, errorMsg, tsListDirFile)
            }
            override fun onComplete(url: String, length: Long, path: String?) {
                onDoComplete(ts, length, tsListDirFile)
            }
        }, header, tag = tag)
        return downloadFileUtils.getDownloadRunnable()
    }

    override fun onProgressCallback() {
        // 回调并更新task的部分数据
        val completeTsCount = m3u8.tsList.count{ it.complete }
        val percent = if (m3u8.tsList.isEmpty()) {
            0f
        } else {
            completeTsCount * 1f/ m3u8.tsList.size
        } * 100
        if (isInterrupted) return
        if (BuildConfig.DEBUG) {
            val speedStr = DownloadConstants.byte2FitMemorySize(currentDownloadSpeed, 2)
            val currentLengthStr = DownloadConstants.byte2FitMemorySize(currentDownloadLength, 2)
            Log.d(WBDownloadUtils.TAG, "${tag} -> onProgress -> $speedStr - $currentLengthStr, ${percent.toInt()}% ")
        }

        listener.onProgress(url, currentDownloadSpeed, currentDownloadLength, percent)
        // 重置下载进度
        currentDownloadSpeed = 0L
        m3u8UpdateInterval++
        if (m3u8UpdateInterval >= 2) { // 更新数据库
            if (isInterrupted) return
            CacheM3U8Utils.cacheM3U8(tag, m3u8)
            m3u8UpdateInterval = 0
        }
    }


    private fun onDoError(ts: Ts, errorMsg: String, tsListDirFile: File){
        if (ts.retryTimes < Params.MIN_DOWNLOAD_RETRY_TIMES) { // 重试，不需要关闭线程池
            if (isInterrupted) return
            if (!NetworkUtils.isConnected()) {
                ts.retryTimes = 0
                ts.isRetrying = false
                cancel()
                listener.onError(url, errorMsg)
                return
            }
            ts.retryTimes++
            // 重新下载
            Log.d(WBDownloadUtils.TAG, "${ts.getTsName()} -> 下载出错, 进行第${ts.retryTimes}次重试...")
            if (isInterrupted) return
            executors.submit(createTsDownloadRunnable(ts, tsListDirFile))
        } else { // 报错
            ts.retryTimes = 0
            if (isInterrupted) return
            cancel()
            listener.onError(url, errorMsg)
        }
    }

    private fun onDoComplete(ts: Ts, tsLength: Long, tsListDirFile: File) {
        ts.retryTimes = 0
        ts.complete = true
        if (ts.isRetrying) {
            Log.d(WBDownloadUtils.TAG, "${ts.getTsName()} -> 完成下载...")
        }
        ts.isRetrying = false
        ts.tsSize = tsLength
        currentDownloadLength += ts.tsSize
        if (m3u8.tsList.all { it.complete }) { // 所有的任务都成功完成
            if (isInterrupted) return
            Log.d(WBDownloadUtils.TAG, "$tag -> 所有的任务都成功完成...")
            cancel()
            listener.onComplete(url, currentDownloadLength, PathUtils.getProxyM3UFile(rootFilePath)?.absolutePath)
        } else {
            if ((executors as ThreadPoolExecutor).queue.isNullOrEmpty()) { // 所有任务都完成，但是有异常导致没有全部成功
                // 此时没有新的下载任务，需要处理此情况，否则可能会出现卡在99.00%的情况
                val unCompleteTasks = m3u8.tsList.filter { !it.complete }
                if (!NetworkUtils.isConnected()) {
                    unCompleteTasks.forEach {
                        it.retryTimes = 0
                        it.isRetrying = false
                    }
                    cancel()
                    listener.onError(url, DownloadConstants.ERROR_NETWORK_NO_CONNECT)
                    return
                }

                Log.e(WBDownloadUtils.TAG, "$tag -> 此时没有新的下载任务，需要处理此情况，否则可能会出现卡在99.00%的情况...")
                unCompleteTasks.forEach { unCompleteTs ->
                    if (!unCompleteTs.isRetrying) {
                        unCompleteTs.retryTimes += 1
                        unCompleteTs.isRetrying = true
                        Log.d(WBDownloadUtils.TAG, "${unCompleteTs.getTsName()} -> 下载出错，准备第${unCompleteTs.retryTimes}次重试！")
                        executors.submit(createTsDownloadRunnable(unCompleteTs, tsListDirFile))
                    } else {
                        Log.e(WBDownloadUtils.TAG, "${unCompleteTs.getTsName()} -> 下载中，等待完成！")
                    }
                }
            }
        }
    }
}

